﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace CtpMaker
{
    class SchemaOne
    {
        //换行符
        private static string enterChar = "\n";

        //生成CtpEnum文件
        public static void MakeCtpEnumFile()
        {
            StreamReader sr = new StreamReader(@"ctp/ThostFtdcUserApiDataType.h", Encoding.Default);
            StreamWriter sw = new StreamWriter(@"ctp/CtpEnum.cs", false, Encoding.Default);

            //文件头部
            sw.WriteLine("using System;");
            sw.WriteLine("");
            sw.WriteLine("namespace CtpApi.Struct");
            sw.WriteLine("{");

            StringBuilder sbField = new StringBuilder();

            //注释行
            string remarkLine = "";
            //枚举类注释行
            string enumremark = "";

            while (!sr.EndOfStream)
            {
                string line = sr.ReadLine().Trim();
                string[] s = line.Split();

                //结构头部
                if (s.Length == 3 && s[0] == "typedef" && s[1] == "char" && s[2].IndexOf('[') < 0)
                {
                    string en = s[2].Replace("TThostFtdc","");
                    string enumName = en.Remove(en.Length - 5);

                    string fields = sbField.ToString();

                    sw.WriteLine("    /// <summary>");
                    sw.WriteLine("    " + enumremark);
                    sw.WriteLine("    /// </summary>");
                    sw.WriteLine("    public enum " + enumName + "Enum : sbyte");
                    sw.WriteLine("    {");
                    sw.Write(fields.Remove(fields.Length-2, 1));
                    sw.WriteLine("    }");
                    sw.WriteLine("");

                    sbField = new StringBuilder();
                }
                //结构字段
                else if (s.Length == 3 && s[0] == "#define")
                {
                    int i = s[1].LastIndexOf('_');
                    string field = s[1].Substring(i+1);

                    sbField.Append("        /// <summary>").Append(enterChar);
                    sbField.Append("        ").Append(remarkLine).Append(enterChar);
                    sbField.Append("        /// </summary>").Append(enterChar);
                    sbField.Append("        ").Append(field).Append(" = (sbyte)").Append(s[2]).Append(",").Append(enterChar);
                }
                //注释行
                else
                {
                    remarkLine = line;
                    if (line.Length > 8 && line.Substring(0, 8) == "///TFtdc") enumremark = line;
                }
            }

            sw.WriteLine("}//namespace");

            sr.Close();
            sw.Close();
        }

        //生成CtpStruct文件
        public static void MakeCtpStructFile()
        {
            StreamReader sr = new StreamReader(@"ctp/ThostFtdcUserApiStruct.h", Encoding.Default);
            StreamWriter sw = new StreamWriter(@"ctp/CtpStruct.cs", false, Encoding.Default);

            //文件头部
            sw.WriteLine("using System;");
            sw.WriteLine("");
            sw.WriteLine("namespace CtpApi.Struct");
            sw.WriteLine("{");

            //注释行
            string remarkLine = "";

            while (!sr.EndOfStream)
            {
                string line = sr.ReadLine().Trim();
                string[] s = line.Split();

                //结构头部
                if (s.Length == 2 && s[0] == "struct")
                {
                    sw.WriteLine("}");
                    sw.WriteLine("");

                    sw.WriteLine("/// <summary>");
                    sw.WriteLine(remarkLine);
                    sw.WriteLine("/// </summary>");
                    sw.WriteLine("public class " + s[1]);
                    sw.WriteLine("{");
                }
                //结构字段
                else if (s.Length == 2 && s[0].Substring(0, 10) == "TThostFtdc")
                {
                    int length = 0;
                    string typeName = "";
                    string fieldName = s[1].Remove(s[1].Length - 1);
                    
                    getDataTypeInfo(s[0], out typeName, out length);

                    sw.WriteLine("    /// <summary>");
                    sw.WriteLine("    " + remarkLine);
                    sw.WriteLine("    /// </summary>");

                    if (typeName == "char")
                        if (length == 1)
                        {
                            string en = s[0].Replace("TThostFtdc", "");
                            string enumName = en.Remove(en.Length - 4);
                            sw.WriteLine("    public " + enumName + "Enum " + fieldName + " { get; set; }");
                        }
                        else
                            sw.WriteLine("    public string " + fieldName + " { get; set; }");
                    else
                        sw.WriteLine("    public " + typeName + " " + fieldName + " { get; set; }");
                }
                else
                {
                    remarkLine = line;
                }
            }

            sw.WriteLine("}");
            sw.WriteLine("");
            sw.WriteLine("}//namespace");

            sr.Close();
            sw.Close();
        }

        //生成转换器类
        public static void MakeConverterFileOld()
        {
            StreamReader sr = new StreamReader(@"ctp/ThostFtdcUserApiStruct.h", Encoding.Default);
            StreamWriter sw = new StreamWriter(@"ctp/CtpConverter.h", false, Encoding.Default);

            StringBuilder sbToManage = new StringBuilder();
            StringBuilder sbToUnmanage = new StringBuilder();

            //文件头部
            sw.WriteLine("#pragma once");
            sw.WriteLine("#include \"Tools.h\"");
            sw.WriteLine("#include \"ThostFtdcUserApiStruct.h\"");
            sw.WriteLine("");
            sw.WriteLine("using namespace System;");
            sw.WriteLine("");
            sw.WriteLine("namespace CtpApi");
            sw.WriteLine("{");

            //注释行
            string remarkLine = "";

            while (!sr.EndOfStream)
            {
                string line = sr.ReadLine().Trim();
                string[] s = line.Split();

                //结构头部
                if (s.Length == 2 && s[0] == "struct")
                {
                    sbToManage.Append(enterChar).Append("        return manageField;").Append(enterChar).Append("    }").Append(enterChar);
                    sbToUnmanage.Append(enterChar).Append("        return unmanageField;").Append(enterChar).Append("    }").Append(enterChar);

                    sw.Write(sbToManage.ToString());
                    sw.WriteLine("");
                    sw.Write(sbToUnmanage.ToString());

                    sw.WriteLine("};");
                    sw.WriteLine("");

                    sbToManage = new StringBuilder();
                    sbToUnmanage = new StringBuilder();

                    sw.WriteLine(remarkLine);
                    sw.WriteLine("private ref class " + s[1] + "Converter");
                    sw.WriteLine("{");
                    sw.WriteLine("public:");

                    sbToManage.Append("    static CtpApi::Struct::").Append(s[1]).Append("^ ToManage(").Append(s[1]).Append("* unmanageField)").Append(enterChar);
                    sbToManage.Append("    {").Append(enterChar);
                    sbToManage.Append("        if (unmanageField == nullptr) return nullptr;").Append(enterChar).Append(enterChar);
                    sbToManage.Append("        CtpApi::Struct::").Append(s[1]).Append("^ manageField = gcnew CtpApi::Struct::").Append(s[1]).Append("();").Append(enterChar);

                    sbToUnmanage.Append("    static ").Append(s[1]).Append("* ToUnmanage(CtpApi::Struct::").Append(s[1]).Append("^ manageField)").Append(enterChar);
                    sbToUnmanage.Append("    {").Append(enterChar);
                    sbToUnmanage.Append("        ").Append(s[1]).Append("* unmanageField = new ").Append(s[1]).Append("();").Append(enterChar);
                }
                //结构字段
                else if (s.Length == 2 && s[0].Substring(0, 10) == "TThostFtdc")
                {
                    int length = 0;
                    string typeName = "";
                    string fieldName = s[1].Remove(s[1].Length - 1);

                    getDataTypeInfo(s[0], out typeName, out length);

                    sbToManage.Append("        " + remarkLine).Append(enterChar);
                    sbToUnmanage.Append("        " + remarkLine).Append(enterChar);

                    if (typeName == "char")
                    {
                        if (length == 1)
                        {
                            sbToManage.Append("        manageField->").Append(fieldName).Append(" = unmanageField->").Append(fieldName).Append(";").Append(enterChar);
                            sbToUnmanage.Append("        unmanageField->").Append(fieldName).Append(" = manageField->").Append(fieldName).Append(";").Append(enterChar);
                        }
                        else
                        {
                            sbToManage.Append("        manageField->").Append(fieldName).Append(" = Tools::ConvertCharToString(unmanageField->").Append(fieldName).Append(");").Append(enterChar);
                            sbToUnmanage.Append("        strcpy_s(unmanageField->").Append(fieldName).Append(",").Append(length).Append(",Tools::ConvertStringToChar(manageField->").Append(fieldName).Append("));").Append(enterChar);
                        }
                    }
                    else
                    {
                        sbToManage.Append("        manageField->").Append(fieldName).Append(" = unmanageField->").Append(fieldName).Append(";").Append(enterChar);
                        sbToUnmanage.Append("        unmanageField->").Append(fieldName).Append(" = manageField->").Append(fieldName).Append(";").Append(enterChar);
                    }
                }
                else
                {
                    remarkLine = line;
                }
            }

            sbToManage.Append(enterChar).Append("        return manageField;").Append(enterChar).Append("    }").Append(enterChar);
            sbToUnmanage.Append(enterChar).Append("        return unmanageField;").Append(enterChar).Append("    }").Append(enterChar);

            sw.Write(sbToManage.ToString());
            sw.WriteLine("");
            sw.Write(sbToUnmanage.ToString());

            sw.WriteLine("};");
            sw.WriteLine("");
            sw.WriteLine("}//namespace");

            sr.Close();
            sw.Close();
        }
        public static void MakeConverterFile()
        {
            StreamReader sr = new StreamReader(@"ctp/ThostFtdcUserApiStruct.h", Encoding.Default);
            StreamWriter sw = new StreamWriter(@"ctp/CtpConverter.h", false, Encoding.Default);

            StringBuilder sbToManage = new StringBuilder();
            StringBuilder sbToUnmanage = new StringBuilder();

            //文件头部
            sw.WriteLine("#pragma once");
            sw.WriteLine("#include \"Tools.h\"");
            sw.WriteLine("#include \"ThostFtdcUserApiStruct.h\"");
            sw.WriteLine("");
            sw.WriteLine("using namespace System;");
            sw.WriteLine("");
            sw.WriteLine("namespace CtpApi");
            sw.WriteLine("{");

            //注释行
            string remarkLine = "";

            while (!sr.EndOfStream)
            {
                string line = sr.ReadLine().Trim();
                string[] s = line.Split();

                //结构头部
                if (s.Length == 2 && s[0] == "struct")
                {
                    sbToManage.Append(enterChar).Append("        return manageField;").Append(enterChar).Append("    }").Append(enterChar);
                    sbToUnmanage.Append(enterChar).Append("        return unmanageField;").Append(enterChar).Append("    }").Append(enterChar);

                    sw.Write(sbToManage.ToString());
                    sw.WriteLine("");
                    sw.Write(sbToUnmanage.ToString());

                    sw.WriteLine("};");
                    sw.WriteLine("");

                    sbToManage = new StringBuilder();
                    sbToUnmanage = new StringBuilder();

                    sw.WriteLine(remarkLine);
                    sw.WriteLine("private ref class " + s[1] + "Converter");
                    sw.WriteLine("{");
                    sw.WriteLine("public:");

                    sbToManage.Append("    static CtpApi::Struct::").Append(s[1]).Append("^ ToManage(").Append(s[1]).Append("* unmanageField)").Append(enterChar);
                    sbToManage.Append("    {").Append(enterChar);
                    sbToManage.Append("        if (unmanageField == nullptr) return nullptr;").Append(enterChar).Append(enterChar);
                    sbToManage.Append("        CtpApi::Struct::").Append(s[1]).Append("^ manageField = gcnew CtpApi::Struct::").Append(s[1]).Append("();").Append(enterChar);

                    sbToUnmanage.Append("    static ").Append(s[1]).Append("* ToUnmanage(CtpApi::Struct::").Append(s[1]).Append("^ manageField)").Append(enterChar);
                    sbToUnmanage.Append("    {").Append(enterChar);
                    sbToUnmanage.Append("        ").Append(s[1]).Append("* unmanageField = new ").Append(s[1]).Append("();").Append(enterChar);
                }
                //结构字段
                else if (s.Length == 2 && s[0].Substring(0, 10) == "TThostFtdc")
                {
                    int length = 0;
                    string typeName = "";
                    string fieldName = s[1].Remove(s[1].Length - 1);

                    string en = s[0].Replace("TThostFtdc", "");
                    string enumName = en.Remove(en.Length - 4) + "Enum";

                    getDataTypeInfo(s[0], out typeName, out length);

                    sbToManage.Append("        " + remarkLine).Append(enterChar);
                    sbToUnmanage.Append("        " + remarkLine).Append(enterChar);

                    if (typeName == "char")
                    {
                        if (length == 1)
                        {
                            sbToManage.Append("        manageField->").Append(fieldName).Append(" = (CtpApi::Struct::").Append(enumName).Append(")unmanageField->").Append(fieldName).Append(";").Append(enterChar);
                            sbToUnmanage.Append("        unmanageField->").Append(fieldName).Append(" = (char)manageField->").Append(fieldName).Append(";").Append(enterChar);
                        }
                        else
                        {
                            sbToManage.Append("        manageField->").Append(fieldName).Append(" = Tools::ConvertCharToString(unmanageField->").Append(fieldName).Append(");").Append(enterChar);
                            sbToUnmanage.Append("        strcpy_s(unmanageField->").Append(fieldName).Append(",").Append(length).Append(",Tools::ConvertStringToChar(manageField->").Append(fieldName).Append("));").Append(enterChar);
                        }
                    }
                    else
                    {
                        sbToManage.Append("        manageField->").Append(fieldName).Append(" = unmanageField->").Append(fieldName).Append(";").Append(enterChar);
                        sbToUnmanage.Append("        unmanageField->").Append(fieldName).Append(" = manageField->").Append(fieldName).Append(";").Append(enterChar);
                    }
                }
                else
                {
                    remarkLine = line;
                }
            }

            sbToManage.Append(enterChar).Append("        return manageField;").Append(enterChar).Append("    }").Append(enterChar);
            sbToUnmanage.Append(enterChar).Append("        return unmanageField;").Append(enterChar).Append("    }").Append(enterChar);

            sw.Write(sbToManage.ToString());
            sw.WriteLine("");
            sw.Write(sbToUnmanage.ToString());

            sw.WriteLine("};");
            sw.WriteLine("");
            sw.WriteLine("}//namespace");

            sr.Close();
            sw.Close();
        }

        //生成CtpEvent文件
        public static void MakeCtpEventFile()
        {
            MakeCtpEventFile("Md", "M");
            MakeCtpEventFile("Trader", "T");
        }
        public static void MakeCtpEventFile(string filename, string t)
        {
            StreamReader sr = new StreamReader(@"ctp/ThostFtdc" + filename + "Api.h", Encoding.Default);
            StreamWriter sw = new StreamWriter(@"ctp/Ctp" + t + "dEvent.h", false, Encoding.Default);

            //文件头部
            sw.WriteLine("#pragma once");
            sw.WriteLine("");
            sw.WriteLine("namespace CtpApi");
            sw.WriteLine("{");
            sw.WriteLine("    public ref class Ctp" + t + "dEvent");
            sw.WriteLine("    {");
            sw.WriteLine("    public:");
            sw.WriteLine("        Ctp" + t + "dEvent(){}");

            //注释行
            string remarkLine = "";
            List<string> internalFun = new List<string>();

            while (!sr.EndOfStream)
            {
                string line = sr.ReadLine().Trim();

                if (line.Length > 15 && line.Substring(0, 15) == "virtual void On")
                {
                    int leftKhIndex = line.IndexOf('(');
                    int rightKhIndex = line.IndexOf(')');

                    string delegateName = line.Substring(15, leftKhIndex - 15);
                    string funParam = line.Substring(leftKhIndex, rightKhIndex - leftKhIndex + 1);
                    string param1 = funParam.Replace("CThostFtdc", "CtpApi::Struct::CThostFtdc").Replace(" *", "^ ");

                    string param2 = "";

                    foreach (string s in funParam.Replace("(", "").Replace(")", "").Split(','))
                    {
                        if (s.IndexOf('*') >= 0)
                            param2 += "CtpApi::" + s.Replace(" *", "Converter::ToManage(").Trim() + "),";
                        else
                            param2 += s.Replace("int ", "").Replace("bool ", "") + ",";
                    }

                    //if (param2.Length > 3)
                    param2 = param2.Remove(param2.Length - 1);

                    sw.WriteLine("        " + remarkLine);
                    sw.WriteLine("        delegate void " + delegateName + param1 + ";");
                    sw.WriteLine("        event " + delegateName + "^ On" + delegateName + ";");
                    sw.WriteLine("");

                    internalFun.Add(remarkLine);
                    internalFun.Add("void Call" + delegateName + funParam + "{ On" + delegateName + "(" + param2 + "); }");
                }
                else
                {
                    remarkLine = line;
                }
            }

            sw.WriteLine("    internal:");

            foreach (string s in internalFun)
            {
                sw.WriteLine("        " + s);
            }

            sw.WriteLine("    };");
            sw.WriteLine("");
            sw.WriteLine("}//namespace");

            sr.Close();
            sw.Close();
        }

        //生成CtpSpi文件
        public static void MakeCtpSpiFile()
        {
            MakeCtpSpiFile("Md", "M");
            MakeCtpSpiFile("Trader", "T");
        }
        public static void MakeCtpSpiFile(string filename, string t)
        {
            StreamReader sr = new StreamReader(@"ctp/ThostFtdc" + filename + "Api.h", Encoding.Default);
            StreamWriter sw = new StreamWriter(@"ctp/Ctp" + t + "dSpi.h", false, Encoding.Default);

            //文件头部
            sw.WriteLine("#pragma once");
            sw.WriteLine("#include \"gcroot.h\"");
            sw.WriteLine("#include \"ThostFtdcMdApi.h\"");
            sw.WriteLine("#include \"ThostFtdcTraderApi.h\"");
            sw.WriteLine("#include \"Ctp" + t + "dEvent.h\"");
            sw.WriteLine("");
            sw.WriteLine("namespace CtpApi");
            sw.WriteLine("{");
            sw.WriteLine("    public class Ctp" + t + "dSpi: public CThostFtdc" + filename + "Spi");
            sw.WriteLine("    {");
            sw.WriteLine("    private:");
            sw.WriteLine("        gcroot<Ctp" + t + "dEvent^> ctp" + t + "dEvent;");
            sw.WriteLine("");
            sw.WriteLine("    public:");
            sw.WriteLine("        Ctp" + t + "dSpi(gcroot<Ctp" + t + "dEvent^> initCtpEvent){ ctp" + t + "dEvent = initCtpEvent; }");
            sw.WriteLine("");

            //注释行
            string remarkLine = "";
            List<string> internalFun = new List<string>();

            while (!sr.EndOfStream)
            {
                string line = sr.ReadLine().Trim();

                if (line.Length > 15 && line.Substring(0, 15) == "virtual void On")
                {
                    int leftKhIndex = line.IndexOf('(');
                    int rightKhIndex = line.IndexOf(')');

                    string delegateName = line.Substring(15, leftKhIndex - 15);
                    string funParam = line.Substring(leftKhIndex + 1, rightKhIndex - leftKhIndex - 1)
                                          .Replace("int ", " ").Replace("bool ", " ");

                    string p1 = "";

                    foreach (string s in funParam.Split(','))
                    {
                        int x = s.IndexOf('*');

                        if (x >= 0)
                            p1 += s.Substring(x + 1, s.Length - x - 1) + ",";
                        else
                            p1 += s.Trim() + ",";
                    }

                    p1 = p1.Remove(p1.Length - 1);

                    sw.WriteLine("        " + remarkLine);
                    sw.WriteLine("        " + line.Remove(0, 8).Replace("{};", "{ ctp" + t + "dEvent->Call" + delegateName + "(" + p1 + "); }"));
                }
                else
                {
                    remarkLine = line;
                }
            }

            sw.WriteLine("    };");
            sw.WriteLine("");
            sw.WriteLine("}//namespace");

            sr.Close();
            sw.Close();
        }

        //生成CtpTdApi文件
        public static void MakeCtpTdApiFile()
        {
            StreamReader sr = new StreamReader(@"ctp/ThostFtdcTraderApi.h", Encoding.Default);
            StreamWriter sw = new StreamWriter(@"ctp/CtpTdApi.h", false, Encoding.Default);

            //注释行
            string remarkLine = "";

            while (!sr.EndOfStream)
            {
                string line = sr.ReadLine().Trim();

                if (line.Length > 15 && line.Substring(0, 15) == "virtual int Req")
                {
                    string s = line.Replace("virtual ", "").Replace("CThostFtdc", "CtpApi::Struct::CThostFtdc").Replace(" *", "^ ").Replace(" = 0;", "");

                    int leftKhIndex = s.IndexOf('(');
                    int f1 = s.IndexOf('^');
                    int f2 = s.IndexOf(',');

                    string funName = s.Substring(4, leftKhIndex - 4);
                    string field = s.Substring(leftKhIndex + 1, f1 - leftKhIndex - 1).Replace("CtpApi::Struct::", "");
                    string param = s.Substring(f1 + 2, f2 - f1 - 2);

                    string s1 = s + "{ return tdApi->" + funName + "(CtpApi::" + field + "Converter::ToUnmanage(" + param + "), nRequestID); }";

                    sw.WriteLine("		" + remarkLine);
                    sw.WriteLine("		" + s1);
                    sw.WriteLine("");
                }
                else
                {
                    remarkLine = line;
                }
            }

            sr.Close();
            sw.Close();
        }

        //获取数据类型信息
        private static void getDataTypeInfo(string fieldName, out string typeName, out int length)
        {
            typeName = ""; length = 1;
            StreamReader srDataType = new StreamReader(@"ctp/ThostFtdcUserApiDataType.h");

            while (!srDataType.EndOfStream)
            {
                string s = srDataType.ReadLine().Trim();

                if (s.IndexOf(fieldName) != -1)
                {
                    string[] words = s.Split();
                    typeName = words[1];

                    if (typeName == "char" && words[2].IndexOf('[') != -1)
                    {
                        int startIndex = words[2].IndexOf('[');
                        int endIndex = words[2].IndexOf(']');
                        length = int.Parse(words[2].Substring(startIndex + 1, endIndex - startIndex - 1));
                    }

                    break;
                }
            }

            srDataType.Close();
        }
    }
}
